﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		PageService.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Dexter.Caching;
using Dexter.Core.EventArgs;
using Dexter.DataTransferObject;
using Dexter.Domain.Model;
using Dexter.Domain.Results;
using Dexter.Logger.Contracts;
using Dexter.Repository;
using Topics.Radical.Validation;

namespace Dexter.Services.Implementation {
	/// <summary>
	/// 	Implementation of <see cref = "IPageService" />
	/// </summary>
	public class PageService : IPageService {
		protected ILogger Logger;
		protected IPageRepository PageRepository;
		protected ICacheProvider CacheProvider;

		public PageService ( IPageRepository repository , ILogger logger , ICacheProvider cacheProvider ) {
			Logger = logger;
			this.CacheProvider = cacheProvider;
			PageRepository = repository;
		}

		public virtual IList<string> GetAllSlugs ( ) {
			var e = new CancelEventArgsWithReturnItem<IList<string>>();

			SlugRetrieving.Raise ( this , e );

			if ( e.Cancel ) {
				return e.ReturnValue;
			}

			var slugs = PageRepository.GetAllPagesSlugs ( );

			SlugRetrieved.Raise ( this , new GenericEventArgs <IList <string>> ( slugs ) );

			return slugs;
		}

		public virtual IEnumerable<PageStructure> GetPagesStructure ( ) {
			var e = new CancelEventArgsWithReturnItem<IEnumerable<PageStructure>>();

			PagesStructureRetrieving.Raise ( this , e );

			if ( e.Cancel ) {
				return e.ReturnValue;
			}

			var pageStructures = PageRepository.GetPagesStructure ( );

			PagesStructureRetrieved.Raise ( this , new GenericEventArgs <IEnumerable <PageStructure>> ( pageStructures ) );

			return pageStructures;
		}

		public IEnumerable <PageStructureDto> GetPagesStructureDto ( ) {
			var value = CacheProvider.Get<IEnumerable<PageStructureDto>> ( "GetPagesStructureDto", CacheRegions.Pages )
				.Return ( o => o,
						  ( ) => {
							  var c = GetPagesStructure ( ).ToDtos ( );

							  CacheProvider.Put ( "GetPagesStructureDto", c, TimeSpan.FromMinutes ( 10 ), CacheRegions.Pages, null );

							  return c;
						  } );

			return value;
		}

		public virtual IEnumerable<PageStructure> GetPagesStructureRoot()
		{
			var e = new CancelEventArgsWithReturnItem<IEnumerable<PageStructure>>();

			PagesStructureRetrieving.Raise(this, e);

			if (e.Cancel)
			{
				return e.ReturnValue;
			}

			var pageStructures = PageRepository.GetPagesStructureRoot();

			PagesStructureRetrieved.Raise(this, new GenericEventArgs<IEnumerable<PageStructure>>(pageStructures));

			return pageStructures;
		}

		public IEnumerable <PageStructureDto> GetPagesStructureDtoRoot ( ) {
			var value = CacheProvider.Get<IEnumerable<PageStructureDto>> ( "GetPagesStructureRoot", CacheRegions.Pages )
				.Return ( o => o,
						  ( ) =>
						  {
							  var c = GetPagesStructureRoot ( ).ToDtos ( );

							  CacheProvider.Put ( "GetPagesStructureRoot", c, TimeSpan.FromMinutes ( 10 ), CacheRegions.Pages, null );

							  return c;
						  } );

			return value;
		}

		public virtual IPagedResult<Page> GetPages ( int pageIndex, int pageSize ) {
			var e = new CancelEventArgsWithOneParameterWithReturnItem<Tuple<int, int>, IPagedResult<Page>>(new Tuple<int, int>(pageIndex, pageSize));
			PagesRetrieving.Raise ( this , e );

			if ( e.Cancel ) {
				return e.ReturnValue;
			}

			var data = PageRepository.GetPages ( pageIndex , pageSize , false );

			PagesRetrieved.Raise ( this , new GenericEventArgs <IPagedResult <Page>> ( data ) );

			return data;
		}

		public virtual Page GetBySlug ( string slug ) {
			return GetBySlug ( slug , false );
		}

		public Page GetBySlug ( string slug , bool enableTracking ) {
			var e = new CancelEventArgsWithOneParameterWithReturnItem<string, Page>(slug);

			PageRetrieving.Raise ( this, e );

			if (e.Cancel) {
				return e.ReturnValue;
			}

			var page = PageRepository.GetBySlug ( slug );

			PageRetrieved.Raise ( this, new GenericEventArgs<Page> ( page ) );

			return page;
		}

		public virtual Page GetByKeyWithParent(int key)
		{
			var e = new CancelEventArgsWithOneParameterWithReturnItem<int, Page>(key);

			PageRetrievingByKey.Raise(this, e);

			if (e.Cancel)
			{
				return e.ReturnValue;
			}

			var page = PageRepository.GetByKeyWithParent(key);

			PageRetrieved.Raise(this, new GenericEventArgs<Page>(page));

			return page;
		}

		public virtual Page GetByKeyWithParent(int key, bool enableTracking)
		{
			var e = new CancelEventArgsWithOneParameterWithReturnItem<int,Page>(key);

			PageRetrievingByKey.Raise(this, e);

			if (e.Cancel)
			{
				return null;
			}

			var page = PageRepository.GetByKeyWithParent(key, enableTracking);

			PageRetrieved.Raise(this, new GenericEventArgs<Page>(page));

			return page;
		}

		public void Delete(int key)
		{
			Ensure.That(key)
				.Named("key")
				.WithPreview((v, e) => Logger.Warn(v.GetFullErrorMessage(), e))
				.IsGreaterThen(0)
				.WithMessage("Invalid page key.");

			var ea = new CancelEventArgsWithOneParameter<int>(key);

			PageDeleting.Raise(this, ea);

			if (ea.Cancel)
			{
				return;
			}

			var page = PageRepository.GetByKey(key);

			PageRepository.Delete(page);

			CacheProvider.ClearRegion ( CacheRegions.Pages );

			PageDeleted.Raise(this, new GenericEventArgs<Page>(page));
		}

		public void Save(Page item)
		{
			var ea = new CancelEventArgsWithOneParameter<Page>(item);

			PageSaving.Raise(this, ea);

			if (ea.Cancel)
			{
				return;
			}

			PrepareItemToSave(item);

			PageRepository.Save(item);

			CacheProvider.ClearRegion ( CacheRegions.Pages );

			PageSaved.Raise(this, new GenericEventArgs<Page>(item));
		}

		public void Update(Page item)
		{
			var ea = new CancelEventArgsWithOneParameter<Page>(item);

			PageUpdating.Raise(this, ea);

			if (ea.Cancel)
			{
				return;
			}

			PrepareItemToSave(item);

			PageRepository.Update(item);

			CacheProvider.ClearRegion ( CacheRegions.Pages );

			PageUpdated.Raise(this, new GenericEventArgs<Page>(item));
		}

		public event EventHandler<CancelEventArgsWithOneParameterWithReturnItem<string, Page>> PageRetrieving;
		public event EventHandler<CancelEventArgsWithOneParameterWithReturnItem<int, Page>> PageRetrievingByKey;
		public event EventHandler<GenericEventArgs<Page>> PageRetrieved;
		public event EventHandler<CancelEventArgsWithOneParameterWithReturnItem<Tuple<int, int>, IPagedResult<Page>>> PagesRetrieving;
		public event EventHandler<GenericEventArgs<IPagedResult<Page>>> PagesRetrieved;
		public event EventHandler<CancelEventArgsWithReturnItem<IEnumerable<PageStructure>>> PagesStructureRetrieving;
		public event EventHandler<GenericEventArgs<IEnumerable<PageStructure>>> PagesStructureRetrieved;
		public event EventHandler<CancelEventArgsWithReturnItem<IList<string>>> SlugRetrieving;
		public event EventHandler<GenericEventArgs<IList<string>>> SlugRetrieved;
		public event EventHandler<CancelEventArgsWithOneParameter<int>> PageDeleting;
		public event EventHandler<GenericEventArgs<Page>> PageDeleted;
		public event EventHandler<CancelEventArgsWithOneParameter<Page>> PageSaving;
		public event EventHandler<GenericEventArgs<Page>> PageSaved;
		public event EventHandler<CancelEventArgsWithOneParameter<Page>> PageUpdating;
		public event EventHandler<GenericEventArgs<Page>> PageUpdated;

		#region "Helpers"

		void PrepareItemToSave(Page item)
		{
			if (string.IsNullOrEmpty(item.Slug))
				item.Slug = PostService.GenerateSlug(item, GetBySlug);
		}

		#endregion
	}
}